home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 2002 November / SGI Freeware 2002 November - Disc 2.iso / dist / fw_glimpse.idb / usr / freeware / src / glimpse-3.0 / split.c.z / split.c
C/C++ Source or Header  |  1997-09-09  |  20KB  |  600 lines

  1. /* Copyright (c) 1994 Burra Gopal, Udi Manber.  All Rights Reserved. */
  2.  
  3. #include "glimpse.h"
  4.  
  5. extern CHAR *getword();
  6. extern int checksg();
  7. extern int D;
  8. extern CHAR GProgname[MAXNAME];
  9. extern FILE *debug;
  10. extern int StructuredIndex;
  11. extern int WHOLEFILESCOPE;
  12. extern int ByteLevelIndex;
  13. extern int ComplexBoolean;
  14. extern int foundattr;
  15.  
  16. /* returns where it found the distinguishing token: until that from prev value of begin is the current pattern (not just the "words" in it) */
  17. CHAR *
  18. parse_flat(begin, end, prev, next)
  19.     CHAR    *begin;
  20.     CHAR    *end;
  21.     int    prev;
  22.     int    *next;
  23. {
  24.     if (begin > end) {
  25.         *next = prev;
  26.         return end;
  27.     }
  28.  
  29.     if (prev & ENDSUB_EXP) prev &= ~ATTR_EXP;
  30.     if ((prev & ATTR_EXP) && !(prev & VAL_EXP)) prev |= VAL_EXP;
  31.  
  32.     while (begin <= end) {
  33.         if (*begin == ',') {
  34.             prev |= OR_EXP;
  35.             prev |= VAL_EXP;
  36.             prev |= ENDSUB_EXP;
  37.             if (prev & AND_EXP) {
  38.                 fprintf(stderr, "%s: parse error at character '%c'\n", GProgname, *begin);
  39.                 return NULL;
  40.             }
  41.             *next = prev;
  42.             return begin;
  43.         }
  44.         else if (*begin == ';') {
  45.             prev |= AND_EXP;
  46.             prev |= VAL_EXP;
  47.             prev |= ENDSUB_EXP;
  48.             if (prev & OR_EXP) {
  49.                 fprintf(stderr, "%s: parse error at character '%c'\n", GProgname, *begin);
  50.                 return NULL;
  51.             }
  52.             *next = prev;
  53.             return begin;
  54.         }
  55.         else if (*begin == '=') {
  56.             if (StructuredIndex <= 0) begin++;    /* don't care about = since just another character */
  57.             else {
  58.                 if (prev & ATTR_EXP) {
  59.                     fprintf(stderr, "%s: syntax error: only ',' and ';' can follow 'attribute=value'\n", GProgname);
  60.                     return NULL;
  61.                 }
  62.                 prev |= ATTR_EXP;    /* remains an ATTR_EXP until a new ',' OR ';' */
  63.                 prev &= ~VAL_EXP;
  64.                 *next = prev;
  65.                 return begin;
  66.             }
  67.         }
  68.         else if (*begin == '\\') begin ++;    /* skip two things */
  69.         begin++;
  70.     }
  71.  
  72.     *next = prev;
  73.     return begin;
  74. }
  75.  
  76. int
  77. split_pattern_flat(GPattern, GM, APattern, terminals, pnum_terminals, pGParse, num_attr)
  78.     CHAR    *GPattern;
  79.     int    GM;
  80.     CHAR    *APattern;
  81.     ParseTree terminals[];
  82.     int    *pnum_terminals;
  83.     int    *pGParse;    /* doesn't interpret it as a tree */
  84.     int    num_attr;
  85. {
  86.     int   j, k = 0, l = 0, len = 0;
  87.     int   current_attr;
  88.     CHAR  *buffer;
  89.     CHAR  *buffer_pat;
  90.     CHAR  *buffer_end;
  91.     char  tempbuf[MAX_LINE_LEN];
  92.  
  93.     memset(APattern, '\0', MAXPAT);
  94.     buffer = GPattern;
  95.     buffer_end = buffer + GM;
  96.     j=0;
  97.     *pGParse = 0;
  98.     current_attr = 0;
  99.     foundattr = 0;
  100.  
  101.     /*
  102.      * buffer is the runnning pointer, buffer_pat is the place where
  103.      * the distinguishing delimiter was found, buffer_end is the end.
  104.      */
  105.      while (buffer_pat = parse_flat(buffer, buffer_end, *pGParse, pGParse)) {
  106.         /* there is no pattern until after the distinguishing delimiter position: some agrep garbage */
  107.         if (buffer_pat <= buffer) {
  108.             buffer = buffer_pat+1;
  109.             if (buffer_pat >= buffer_end) break;
  110.             continue;
  111.         }
  112.         if ((*pGParse & ATTR_EXP) && !(*pGParse & VAL_EXP)) {    /* fresh attribute */
  113.             foundattr=1;
  114.             memcpy(tempbuf, buffer, buffer_pat - buffer);
  115.             tempbuf[buffer_pat - buffer] = '\0';
  116.             len = strlen(tempbuf);
  117.             for (k = 0; k<len; k++) {
  118.                 if (tempbuf[k] == '\\') {
  119.                     for (l=k; l<len; l++)
  120.                         tempbuf[l] = tempbuf[l+1];
  121.                     len --;
  122.                 }
  123.             }
  124.             if ( ((current_attr = attr_name_to_id(tempbuf, len)) <= 0) || (current_attr >= num_attr)) {
  125.                 buffer[buffer_pat - buffer] = '\0';
  126.                 fprintf(stderr, "%s: unknown attribute name '%s'\n", GProgname, buffer);
  127.                 return -1;
  128.             }
  129.  
  130.             buffer = buffer_pat+1;    /* immediate next character after distinguishing delimiter */
  131.             if (buffer_pat >= buffer_end) break;
  132.             continue;
  133.         }
  134.         else {    /* attribute's value OR raw-value */
  135.             if (*pnum_terminals >= MAXNUM_PAT) {
  136.                 fprintf(stderr, "%s: boolean expression has too many terms\n", GProgname);
  137.                 return -1;
  138.             }
  139.             terminals[*pnum_terminals].op = 0;
  140.             terminals[*pnum_terminals].type = LEAF;
  141.             terminals[*pnum_terminals].terminalindex = *pnum_terminals;
  142.             terminals[*pnum_terminals].data.leaf.attribute = (unsigned char *)current_attr;    /* default is no structure */
  143.             terminals[*pnum_terminals].data.leaf.value = (CHAR *)malloc(buffer_pat - buffer + 2);
  144.             memcpy(terminals[*pnum_terminals].data.leaf.value, buffer, buffer_pat - buffer);    /* without distinguishing delimiter */
  145.             terminals[*pnum_terminals].data.leaf.value[buffer_pat - buffer] = '\0';
  146.             if (foundattr || WHOLEFILESCOPE) {
  147.                 memcpy(&APattern[j], buffer, buffer_pat - buffer);
  148.                 j += buffer_pat - buffer;    /* NOT including the distinguishing delimiter at buffer_pat, or '\0' */
  149.                 APattern[j++] = (*(buffer_pat + 1) == '\0' ? '\0' : ',');    /* always search for OR, do filtering at the end */
  150. #if    BG_DEBUG
  151.                 fprintf(debug, "current_attr = %d, val = %s\n", current_attr, terminals[*pnum_terminals].data.leaf.value);
  152. #endif    /*BG_DEBUG*/
  153.             }
  154.             else {
  155.                 memcpy(&APattern[j], buffer, buffer_pat + 1 - buffer);
  156.                 j += buffer_pat + 1 - buffer;    /* including the distinguishing delimiter at buffer_pat, or '\0' */
  157.             }
  158.             (*pnum_terminals)++;
  159.         }
  160.         if (*pGParse & ENDSUB_EXP) current_attr = 0;    /* remains 0 until next fresh attribute */
  161.         if (buffer_pat >= buffer_end) break;
  162.         buffer = buffer_pat+1;
  163.     }
  164.     if (buffer_pat == NULL) return -1;    /* got out of while loop because of NULL rather than break */
  165.     APattern[j] = '\0';
  166.  
  167.     if (foundattr || WHOLEFILESCOPE)    /* then search must always be OR since scope is over whole files */
  168.         for (j=0; APattern[j] != '\0'; j++)
  169.             if (APattern[j] == '\\') j++;
  170.             else if (APattern[j] == ';') APattern[j] = ',';
  171.     return(*pnum_terminals);
  172. }
  173.  
  174. extern int is_complex_boolean();    /* use the one in agrep/asplit.c */
  175. extern int get_token_bool();    /* use the one in agrep/asplit.c */
  176.  
  177. /* Spaces ARE significant: 'a1=v1' and 'a1=v1 ' and 'a1 =v1' etc. are NOT identical */
  178. int
  179. get_attribute_value(pattr, pval, tokenbuf, tokenlen, num_attr)
  180.     int    *pattr, tokenlen;
  181.     CHAR    **pval, *tokenbuf;
  182. {
  183.     CHAR    tempbuf[MAXNAME];
  184.     int    i = 0, j = 0, k = 0, l = 0;
  185.  
  186.     while (i < tokenlen) {
  187.         if (tokenbuf[i] == '\\') {
  188.             tempbuf[j++] = tokenbuf[i++];
  189.             tempbuf[j++] = tokenbuf[i++];
  190.         }
  191.         else if (StructuredIndex) {
  192.             if (tokenbuf[i] == '=') {
  193.                 i++;    /* skip over = : now @ 1st char of value */
  194.                 tempbuf[j] = '\0';
  195.                 for (k=0; k<j; k++) {
  196.                     if (tempbuf[k] == '\\') {
  197.                         for (l=k; l<j; l++)
  198.                             tempbuf[l] = tempbuf[l+1];
  199.                         j --;
  200.                     }
  201.                 }
  202.                 if ( ((*pattr = attr_name_to_id(tempbuf, j)) <= 0) || (*pattr >= num_attr) ) {    /* named a non-existent attribute */
  203.                     fprintf(stderr, "%s: unknown attribute name '%s'\n", GProgname, tempbuf);
  204.                     return 0;
  205.                 }
  206.                 *pval = (CHAR *)malloc(tokenlen - i + 2);
  207.                 memcpy(*pval, &tokenbuf[i], tokenlen - i);
  208.                 (*pval)[tokenlen - i] = '\0';
  209.                 foundattr = 1;
  210.                 return 1;
  211.             }
  212.             else tempbuf[j++] = tokenbuf[i++];    /* consider = as just another char */
  213.         }
  214.         else tempbuf[j++] = tokenbuf[i++];    /* no attribute parsing */
  215.     }
  216.     /* Not a structured expression */
  217.     tempbuf[j] = '\0';
  218.     *pval = (CHAR *)malloc(j + 2);
  219.     memcpy(*pval, tempbuf, j);
  220.     (*pval)[j] = '\0';
  221.     return 1;
  222. }
  223.  
  224. extern destroy_tree();    /* use the one in agrep/asplit.c */
  225.  
  226. /*
  227.  * Recursive descent; C-style => AND + OR have equal priority => must bracketize expressions appropriately or will go left->right.
  228.  * Also strips out attribute names since agrep doesn't understand them: copies resulting pattern for agrep-ing into apattern.
  229.  * Grammar:
  230.  *     E = {E} | ~a | ~{E} | E ; E | E , E | a
  231.  * Parser:
  232.  *    One look ahead at each literal will tell you what to do.
  233.  *    ~ has highest priority, ; and , have equal priority (left to right associativity), ~~ is not allowed.
  234.  */
  235. ParseTree *
  236. parse_tree(buffer, len, bufptr, apattern, apatptr, terminals, pnum_terminals, num_attr)
  237.     CHAR    *buffer;
  238.     int    len;
  239.     int    *bufptr;
  240.     CHAR    *apattern;
  241.     int    *apatptr;
  242.     ParseTree terminals[];
  243.     int    *pnum_terminals;
  244.     int    num_attr;
  245. {
  246.     int    token, tokenlen;
  247.     CHAR    tokenbuf[MAXNAME];
  248.     int    oldtokenlen;
  249.     CHAR    oldtokenbuf[MAXNAME];
  250.     ParseTree *t, *n, *leftn;
  251.  
  252.     token = get_token_bool(buffer, len, bufptr, tokenbuf, &tokenlen);
  253.     switch(token)
  254.     {
  255.     case    '{':    /* (exp) */
  256.         apattern[(*apatptr)++] = '{';
  257.         if ((t = parse_tree(buffer, len, bufptr, apattern, apatptr, terminals, pnum_terminals, num_attr)) == NULL) return NULL;
  258.         if ((token = get_token_bool(buffer, len, bufptr, tokenbuf, &tokenlen)) != '}') {
  259.             fprintf(stderr, "%s: parse error at offset %d\n", GProgname, *bufptr);
  260.             destroy_tree(t);
  261.             return (NULL);
  262.         }
  263.         apattern[(*apatptr)++] = '}';
  264.         if ((token = get_token_bool(buffer, len, bufptr, tokenbuf, &tokenlen)) == 'e') return t;
  265.         switch(token)
  266.         {
  267.         /* must find boolean infix operator */
  268.         case ',':
  269.         case ';':
  270.             apattern[(*apatptr)++] = token;
  271.             leftn = t;
  272.             if ((t = parse_tree(buffer, len, bufptr, apattern, apatptr, terminals, pnum_terminals, num_attr)) == NULL) return NULL;
  273.             n = (ParseTree *)malloc(sizeof(ParseTree));
  274.             n->op = (token == ';') ? ANDPAT : ORPAT ;
  275.             n->type = INTERNAL;
  276.             n->data.internal.left = leftn;
  277.             n->data.internal.right = t;
  278.             return n;
  279.  
  280.         /* or end of parent sub expression */
  281.         case '}':
  282.             unget_token_bool(bufptr, tokenlen);    /* part of someone else who called me */
  283.             return t;
  284.  
  285.         default:
  286.             destroy_tree(t);
  287.             fprintf(stderr, "%s: parse error at offset %d\n", GProgname, *bufptr);
  288.             return NULL;
  289.         }
  290.  
  291.     /* Go one level deeper */
  292.     case    '~':    /* not exp */
  293.         apattern[(*apatptr)++] = '~';
  294.         if ((token = get_token_bool(buffer, len, bufptr, tokenbuf, &tokenlen)) == 'e') return NULL;
  295.         switch(token)
  296.         {
  297.         case 'a':
  298.             if (*pnum_terminals >= MAXNUM_PAT) {
  299.                 fprintf(stderr, "%s: pattern expression too long (> %d terms)\n", GProgname, MAXNUM_PAT);
  300.                 return NULL;
  301.             }
  302.             n = &terminals[*pnum_terminals];
  303.             n->op = 0;
  304.             n->type = LEAF;
  305.             n->terminalindex = (*pnum_terminals);
  306.             n->data.leaf.value = NULL;
  307.             n->data.leaf.attribute = 0;
  308.             if (!get_attribute_value((int *)&n->data.leaf.attribute, &n->data.leaf.value, tokenbuf, tokenlen, num_attr)) return NULL;
  309.             strcpy(&apattern[*apatptr], n->data.leaf.value);
  310.             *apatptr += strlen(n->data.leaf.value);
  311.             (*pnum_terminals)++;
  312.             n->op |= NOTPAT;
  313.             t = n;
  314.             break;
  315.  
  316.         case '{':
  317.             apattern[(*apatptr)++] = token;
  318.             if ((t = parse_tree(buffer, len, bufptr, apattern, apatptr, terminals, pnum_terminals, num_attr)) == NULL) return NULL;
  319.             if (t->op & NOTPAT) t->op &= ~NOTPAT;
  320.             else t->op |= NOTPAT;
  321.             if ((token = get_token_bool(buffer, len, bufptr, tokenbuf, &tokenlen)) != '}') {
  322.                 fprintf(stderr, "%s: parse error at offset %d\n", GProgname, *bufptr);
  323.                 destroy_tree(t);
  324.                 return NULL;
  325.             }
  326.             break;
  327.  
  328.         default:
  329.             fprintf(stderr, "%s: parse error at offset %d\n", GProgname, *bufptr);
  330.             return NULL;
  331.         }
  332.         /* The resulting tree is in t. Now do another lookahead at this level */
  333.  
  334.         if ((token = get_token_bool(buffer, len, bufptr, tokenbuf, &tokenlen)) == 'e') return t;
  335.         switch(token)
  336.         {
  337.         /* must find boolean infix operator */
  338.         case ',':
  339.         case ';':
  340.             apattern[(*apatptr)++] = token;
  341.             leftn = t;
  342.             if ((t = parse_tree(buffer, len, bufptr, apattern, apatptr, terminals, pnum_terminals, num_attr)) == NULL) return NULL;
  343.             n = (ParseTree *)malloc(sizeof(ParseTree));
  344.             n->op = (token == ';') ? ANDPAT : ORPAT ;
  345.             n->type = INTERNAL;
  346.             n->data.internal.left = leftn;
  347.             n->data.internal.right = t;
  348.             return n;
  349.  
  350.         case '}':
  351.             unget_token_bool(bufptr, tokenlen);
  352.             return t;
  353.  
  354.         default:
  355.             destroy_tree(t);
  356.             fprintf(stderr, "%s: parse error at offset %d\n", GProgname, *bufptr);
  357.             return NULL;
  358.         }
  359.  
  360.     case    'a':    /* individual term (attr=val) */
  361.         if (tokenlen == 0) return NULL;
  362.         memcpy(oldtokenbuf, tokenbuf, tokenlen);
  363.         oldtokenlen = tokenlen;
  364.         oldtokenbuf[oldtokenlen + 1] = '\0';
  365.         token = get_token_bool(buffer, len, bufptr, tokenbuf, &tokenlen);
  366.         switch(token)
  367.         {
  368.         case '}':    /* part of case '{' above: else syntax error not detected but semantics ok */
  369.             unget_token_bool(bufptr, tokenlen);
  370.         case 'e':    /* endof input */
  371.         case ',':
  372.         case ';':
  373.             if (*pnum_terminals >= MAXNUM_PAT) {
  374.                 fprintf(stderr, "%s: pattern expression too long (> %d terms)\n", GProgname, MAXNUM_PAT);
  375.                 return NULL;
  376.             }
  377.             n = &terminals[*pnum_terminals];
  378.             n->op = 0;
  379.             n->type = LEAF;
  380.             n->terminalindex = (*pnum_terminals);
  381.             n->data.leaf.value = NULL;
  382.             n->data.leaf.attribute = 0;
  383.             if (!get_attribute_value((int *)&n->data.leaf.attribute, &n->data.leaf.value, oldtokenbuf, oldtokenlen, num_attr)) return NULL;
  384.             strcpy(&apattern[*apatptr], n->data.leaf.value);
  385.             *apatptr += strlen(n->data.leaf.value);
  386.             (*pnum_terminals)++;
  387.             if ((token == 'e') || (token == '}')) return n;    /* nothing after terminal in expression */
  388.  
  389.             leftn = n;
  390.             apattern[(*apatptr)++] = token;
  391.             if ((t = parse_tree(buffer, len, bufptr, apattern, apatptr, terminals, pnum_terminals, num_attr)) == NULL) return NULL;
  392.             n = (ParseTree *)malloc(sizeof(ParseTree));
  393.             n->op = (token == ';') ? ANDPAT : ORPAT ;
  394.             n->type = INTERNAL;
  395.             n->data.internal.left = leftn;
  396.             n->data.internal.right = t;
  397.             return n;
  398.  
  399.         default:
  400.             fprintf(stderr, "%s: parse error at offset %d\n", GProgname, *bufptr);
  401.             return NULL;
  402.         }
  403.  
  404.     case    'e':    /* can't happen as I always do a lookahead above and return current tree if e */
  405.     default:
  406.         fprintf(stderr, "%s: parse error at offset %d\n", GProgname, *bufptr);
  407.         return NULL;
  408.     }
  409. }
  410.  
  411. int
  412. split_pattern(GPattern, GM, APattern, terminals, pnum_terminals, pGParse, num_attr)
  413.     CHAR    *GPattern;
  414.     int    GM;
  415.     CHAR    *APattern;
  416.     ParseTree terminals[];
  417.     int    *pnum_terminals;
  418.     ParseTree **pGParse;
  419.     int    num_attr;
  420. {
  421.     int    bufptr = 0, apatptr = 0, ret, i, j;
  422.  
  423.     foundattr = 0;
  424.     if (is_complex_boolean(GPattern, GM)) {
  425.         ComplexBoolean = 1;
  426.         *pnum_terminals = 0;
  427.         if ((*pGParse = parse_tree(GPattern, GM, &bufptr, APattern, &apatptr, terminals, pnum_terminals, num_attr)) == NULL)
  428.             return -1;
  429.         /* print_tree(*pGParse, 0); */
  430.         APattern[apatptr] = '\0';
  431.         if (foundattr || WHOLEFILESCOPE) {    /* Search in agrep must always be OR since scope is whole file */
  432.             int    i, j;
  433.  
  434.             for (i=0; i<apatptr; i++) {
  435.                 if (APattern[i] == '\\') i++;
  436.                 else if (APattern[i] == ';') APattern[i] = ',';
  437.                 else if ((APattern[i] == '~') || (APattern[i] == '{') || (APattern[i] == '}')) {
  438.                     /* eliminate it from pattern by shifting (including '\0') since agrep must essentially do a flat search */
  439.                     for (j=i; j<apatptr; j++)
  440.                         APattern[j] = APattern[j+1];
  441.                     apatptr --;
  442.                     i--;    /* to counter the ++ on top */
  443.                 }
  444.             }
  445.         }
  446.         return *pnum_terminals;
  447.     }
  448.     else {
  449.         for (i=0; i<GM; i++) {
  450.             if (GPattern[i] == '\\') i++;
  451.             else if ((GPattern[i] == '{') || (GPattern[i] == '}')) {
  452.                 /* eliminate it from pattern by shifting (including '\0') since agrep must essentially do a flat search */
  453.                 for (j=i; j<GM; j++)
  454.                     GPattern[j] = GPattern[j+1];
  455.                 GM --;
  456.                 i--;    /* counter the ++ on top */
  457.             }
  458.         }
  459.  
  460.         ComplexBoolean = 0;
  461.         *pnum_terminals = 0;
  462.         if ((ret = split_pattern_flat(GPattern, GM, APattern, terminals, pnum_terminals, (int *)pGParse, num_attr)) == -1)
  463.             return -1;
  464.         return ret;
  465.     }
  466. }
  467.  
  468. int eval_tree();    /* use the one in agrep/asplit.c */
  469.  
  470. /* MUST CHANGE ALL memgreps TO USE EXEC DIRECTLY IF POSSIBLE (LAST PRIORITY) */
  471.  
  472. /* All borrowed from main.c and are needed for searching the index */
  473. extern    CHAR    *pat_list[MAXNUM_PAT];  /* complete words within global pattern */
  474. extern    int    pat_lens[MAXNUM_PAT];   /* their lengths */
  475. extern    int    pat_attr[MAXNUM_PAT];   /* set of attributes */
  476. extern    int    num_pat;
  477. extern    CHAR    pat_buf[(MAXNUM_PAT + 2)*MAXPAT];
  478. extern    int    pat_ptr;
  479. extern    int    is_mgrep_pat[MAXNUM_PAT];
  480. extern    int    mgrep_pat_index[MAXNUM_PAT];
  481. extern    int    num_mgrep_pat;
  482. extern    struct offsets **src_offset_table;
  483. extern    struct offsets **curr_offset_table;
  484. extern    char    tempfile[];
  485. extern    int    patindex;
  486. extern    int    patbufpos;
  487. extern    ParseTree terminals[MAXNUM_PAT];
  488. extern    int    num_terminals;
  489. extern int INVERSE;    /* agrep's global: need here to implement ~ in index-search */
  490.  
  491. /* [first, last) = C-style range for which we want the words in terminal-values' patterns: 0..num_terminals for !ComplexBoolean, term/term otherwise */
  492. split_terminal(first, last)
  493.     int    first, last;
  494. {
  495.         CHAR    *buffer;
  496.         CHAR    *buffer_new;
  497.         CHAR    *buffer_end;
  498.         CHAR    *bp;
  499.         CHAR    word[MAXNAME];
  500.         int    word_length;
  501.         int    type;
  502.     int    i, j, k, attribute;
  503.     char    *substring;    /* used with strstr(superstring, substring) */
  504.  
  505.     pat_ptr = 0;
  506.     num_mgrep_pat = 0;
  507.     num_pat = 0;
  508.  
  509.     for (; first<last; first++) {
  510.         attribute = (int)terminals[first].data.leaf.attribute;
  511.         buffer = terminals[first].data.leaf.value;
  512.         buffer_end = buffer + strlen(terminals[first].data.leaf.value);
  513.  
  514.                 /* Now find out which; are the "words" we can search for in the index: each attr_val can have many words in it: e.g., "AUTHOR=Udi Manber" */
  515.                 while ((buffer_new = getword("stdin", word, buffer, buffer_end, NULL)) <= buffer_end) {
  516.                         word_length = strlen(word);
  517.                         if (word_length <= 0) {
  518.                                 buffer = buffer_new;
  519.                                 if (buffer_new >= buffer_end) break;
  520.                                 continue;
  521.                         }
  522.                         if ((type = checksg(word, D, 0)) == -1) return -1;
  523.             if (!type && ComplexBoolean) {
  524.                 fprintf(stderr, "%s: query has complex patterns (like '.*') or options (like -n)\n... cannot search for arbitrary booleans\n", GProgname);
  525.                 return -1;
  526.             }
  527.  
  528.             if (type) {
  529.                 /* Check if superstring: if so, ditch word */
  530.                 for (i=0; i<num_pat; i++) {
  531.                     if (!is_mgrep_pat[i]) continue;
  532.                     substring = strstr(word, pat_list[i]);
  533.                     if ((substring != NULL) && (substring[0] != '\0')) break;
  534.                 }
  535.                 if (i < num_pat) {    /* printf("%s superstring of %s\n", word, pat_list[i]); */
  536.                     if (pat_attr[i] != attribute) pat_attr[i] = 0;    /* union of two unequal attributes is all attributes */
  537.                     buffer = buffer_new;
  538.                     if (buffer_new >= buffer_end) break;
  539.                     continue;
  540.                 }
  541.                 /* Check if substring: delete all superstrings */
  542.                 for (i=0; i<num_pat; i++) {
  543.                     if (!is_mgrep_pat[i]) continue;
  544.                     substring = strstr(pat_list[i], word);
  545.                     if ((substring != NULL) && (substring[0] != '\0')) {    /* printf("%s substring of %s\n", word, pat_list[i]); */
  546.                         if (pat_attr[i] != attribute) attribute = 0;    /* union of two unequal attributes is all attributes */
  547.                         free(pat_list[i]);
  548.                         for (j=i; j<num_pat; j++) {
  549.                             pat_list[j] = pat_list[j+1];
  550.                             pat_lens[j] = pat_lens[j+1];
  551.                             is_mgrep_pat[j] = is_mgrep_pat[j+1];
  552.                             pat_attr[j] = pat_attr[j+1];
  553.                         }
  554.                         num_pat --;
  555.                         for (j=0; j<num_mgrep_pat; j++) {
  556.                             if (mgrep_pat_index[j] == i) {
  557.                                 for (k=j; k<num_mgrep_pat; k++) {
  558.                                     mgrep_pat_index[k] = mgrep_pat_index[k+1] - 1;
  559.                                 }
  560.                                 num_mgrep_pat --;
  561.                                 break;
  562.                             }
  563.                         }
  564.                         i--;    /* to counter the ++ on top */
  565.                     }
  566.                 }
  567.             }
  568.  
  569.                         buffer = buffer_new;
  570.                         bp = (CHAR *) malloc(sizeof(CHAR) * word_length + 2);
  571.                         if(bp == NULL) {
  572.                                 fprintf(stderr, "%s: malloc failed in %s:%d\n", GProgname, __FILE__, __LINE__);
  573.                                 return -1;
  574.                         }
  575.                         pat_list[num_pat] = bp;
  576.                         pat_lens[num_pat] = word_length;
  577.                         is_mgrep_pat[num_pat] = type;
  578.                         pat_attr[num_pat] = attribute;
  579.                         strcpy(pat_list[num_pat], word);
  580.             pat_list[num_pat][word_length] = '\0';
  581.             num_pat ++;
  582. #if     BG_DEBUG
  583.                         fprintf(debug, "word=%s\n", word);
  584. #endif  /*BG_DEBUG*/
  585.                         if(buffer_new >= buffer_end) break;
  586.                         if(num_pat >= MAXNUM_PAT) {
  587.                                 fprintf(stderr, "%s: Warning! too many words in pattern (> %d): ignoring...\n", GProgname, MAXNUM_PAT);
  588.                                 break;
  589.                         }
  590.                 }
  591.     }
  592.     for (i=0; i<num_pat; i++) {
  593.         strcpy(&pat_buf[pat_ptr], pat_list[i]);
  594.         pat_buf[pat_ptr + pat_lens[i]] = '\n';
  595.         pat_buf[pat_ptr + pat_lens[i] + 1] = '\0';
  596.         pat_ptr += (pat_lens[i] + 1);
  597.     }
  598.     return num_pat;
  599. }
  600.